<template>
  <div class="r-cropper-container">
    <div class="r-cropper-body">
      <div class="r-cropper-image">
        <img ref="target" :src="props.src" alt="" />
        <AUploadDragger
          v-show="instance === null"
          class="upload-image"
          :beforeUpload="onSelectImage"
          :showUploadList="false"
        >
          <div class="upload-image__text">单击或拖动文件到此区域选择图片</div>
        </AUploadDragger>
      </div>
    </div>
    <div class="r-cropper-operate">
      <AUpload :beforeUpload="onSelectImage" :showUploadList="false">
        <AButton>
          <UploadOutlined />
        </AButton>
      </AUpload>
      <ASpaceCompact>
        <AButton @click="onDragModeChange">
          <ModeIcon />
        </AButton>
        <AButton @click="() => instance?.zoom(0.1)">
          <ZoomInOutlined />
        </AButton>
        <AButton @click="() => instance?.zoom(-0.1)">
          <ZoomOutOutlined />
        </AButton>
        <AButton @click="() => instance?.rotate(-90)">
          <UndoOutlined />
        </AButton>
        <AButton @click="() => instance?.rotate(90)">
          <RedoOutlined />
        </AButton>
        <AButton @click="() => instance?.scaleX(scaleX ? 1 : -1) && setScaleX(!scaleX)">
          <ColumnWidthOutlined />
        </AButton>
        <AButton @click="() => instance?.scaleY(scaleY ? 1 : -1) && setScaleY(!scaleY)">
          <ColumnHeightOutlined />
        </AButton>
      </ASpaceCompact>

      <AButton v-show="showSubmit" @click="onFinish">确定</AButton>
    </div>
  </div>
</template>

<script setup>
import { onMounted, ref, toValue, computed } from 'vue';
import {
  UploadOutlined,
  StopOutlined,
  ScissorOutlined,
  DragOutlined,
  ZoomInOutlined,
  ZoomOutOutlined,
  UndoOutlined,
  RedoOutlined,
  ColumnWidthOutlined,
  ColumnHeightOutlined
} from '@ant-design/icons-vue';
import Cropper from 'cropperjs';
import 'cropperjs/dist/cropper.css';
import { useState } from '@/hooks';

defineOptions({
  inheritAttrs: false
});

const props = defineProps({
  cropper: { type: Object, default: null },
  aspectRatio: { typeof: 'number', default: 16 / 9 },
  autoCropArea: { typeof: 'number', default: 0.8 },
  src: { type: String, default: '' },
  showSubmit: { type: Boolean, default: true }
});

const emit = defineEmits(['update:cropper', 'finish']);

const target = ref(null);
const [instance, setInstance] = useState(props.cropper);
const [scaleX, setScaleX] = useState(false);
const [scaleY, setScaleY] = useState(false);

const modeType = [
  { key: 'none', icon: StopOutlined },
  { key: 'crop', icon: ScissorOutlined },
  { key: 'move', icon: DragOutlined }
];

const ModeIcon = computed(() => {
  const dragMode = toValue(instance)?.options?.dragMode || 'crop';
  return modeType.find(({ key }) => key === dragMode)?.icon;
});

const create = () => {
  const options = {
    ...props,
    viewMode: 0,
    dragMode: 'crop',
    toggleDragModeOnDblclick: true
  };
  const cropper = new Cropper(toValue(target), options);
  setInstance(cropper);
  emit('update:cropper', cropper);
};

onMounted(() => props.src && create());

const onSelectImage = (file) => {
  const url = URL.createObjectURL(file);
  toValue(instance) === null && create();
  toValue(instance)?.replace(url);
  return false;
};

const onDragModeChange = () => {
  const dragMode = toValue(instance).options.dragMode;
  const index = modeType.findIndex(({ key }) => key === dragMode);
  const mode = modeType[index + 1]?.key || modeType[0].key;
  toValue(instance).setDragMode(mode);
};

const onFinish = () => {
  const cropper = toValue(instance);
  cropper?.getCroppedCanvas().toBlob((blob) => emit('finish', blob));
};
</script>

<style lang="scss" scoped>
.r-cropper-container {
  width: 100%;
  height: 100%;
  overflow: hidden;

  .r-cropper-body {
    width: 100%;
    height: 300px;

    .r-cropper-image {
      height: 100%;
      aspect-ratio: 16 / 9;
      margin: auto;
      position: relative;

      img {
        width: 100%;
        height: 100%;
        object-fit: cover;
      }

      .upload-image {
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
        z-index: 1;
        position: absolute;
        background-color: #fff;

        &__text {
          width: 100%;
          height: 100%;
          display: flex;
          justify-content: center;
          align-items: center;
        }
      }
    }
  }

  .r-cropper-operate {
    width: 100%;
    height: auto;
    display: flex;
    justify-content: center;
    gap: 8px;
    margin-top: 16px;
  }
}
</style>
